/**
 * 判断是否未定义
 * @param v 变量
 * @returns 如果变量定义则返回true,否则返回false
 */
export const isUndef = (v: unknown): boolean => v === undefined || v === null;
export const isDef = (v: unknown): boolean => v != undefined && v != null;

/**
 * 清除对象中的字符串前后空格
 * @param target 目标对象
 * @returns 去除前后空格后的对象
 */
export const recordValueTrim = (target: Record<string, any>) => {
  // 不为空且是对象或数组
  if (target && typeof target === 'object') {
    // 如果数组则使用数组解构，如果是对象则使用对象结构
    const query: Record<string, any> = target instanceof Array ? [...target] : { ...target };
    const keys = Object.keys(query);
    keys.forEach(key => {
      // 是string则进行trim
      if (typeof query[key] === 'string') {
        query[key] = (query[key] as string).trim();
        return;
      }
      // 如果是数组，则递归处理
      if (query[key] instanceof Array) {
        query[key] = query[key].map((item: any) => {
          return typeof item === 'string' ? item.trim() : recordValueTrim(item);
        });
        return;
      }
      // 如果是对象则处理对象
      if (typeof query[key] === 'object') {
        query[key] = recordValueTrim(query[key]);
      }
    });

    return query;
  }

  return target;
};

type FlattenDeepByKey = <T = any>(list: Array<T>, key: keyof T) => T[];
/**
 * 通过指定key深度递归扁平化数组
 * @param list 要扁平化的数组
 * @param key 扁平化依据的字段
 * @returns 返回扁平化后的数组
 */
export const flattenDeepByKey: FlattenDeepByKey = (list, key) => {
  return list.reduce(
    (prev: Parameters<FlattenDeepByKey>[0], curr: Parameters<FlattenDeepByKey>[0][0]) => [
      ...prev,
      curr,
      ...((curr as any)[key] ? flattenDeepByKey((curr as any)[key], key) : []),
    ],
    [],
  ) as ReturnType<FlattenDeepByKey>;
};

export type classNamesOptions = Array<Record<string, any> | string> | Record<string, any> | string;
/**
 * 根据条件判断生产className
 * @param options classNamesOptions
 * @returns 返回实际渲染的className
 */
export const classNames = (options: classNamesOptions): string | undefined => {
  if (typeof options === 'string') {
    return options;
  }

  if (options instanceof Array) {
    return options.map(classNames).join(' ');
  }

  const isDef = !isUndef(options);
  if (isDef && typeof options === 'object') {
    return Object.keys(options)
      .filter((key: string) => !!options[key])
      .join(' ');
  }

  return undefined;
};
